feat: GroupKeyHolder for GMS key management#449
Conversation
12ef35b to
4938373
Compare
9822584 to
1fdc2da
Compare
58cf9ef to
636fc9d
Compare
f8fd4c8 to
6504d1f
Compare
Pravdyvy
left a comment
There was a problem hiding this comment.
Thank you for PR. Left a couple of questions.
6504d1f to
9927e6e
Compare
schouhy
left a comment
There was a problem hiding this comment.
Thanks for the PR. Leaving some thoughts while I finish reviewing
Arjentix
left a comment
There was a problem hiding this comment.
Thanks for the PR. Left some small comments.
I didn't quite get how it works, probably more examples like k/nsignatures program and an integration test demonstrating it would be nice
|
|
schouhy
left a comment
There was a problem hiding this comment.
Hey thanks. Have some general comments about the approach
- Add SealingPublicKey/SealingSecretKey type aliases for seal_for/unseal - Generalize PrivateGroupPda to PrivatePda with pre-resolved keys - Rename group_pda_spender to private_pda_spender - Rename group_pda_accounts to pda_accounts with serde alias - Remove unused storage_mut() - Remove stale group_pda_router.bin artifact
schouhy
left a comment
There was a problem hiding this comment.
Thanks LGTM. I'd personally remove the epoch, ratcheting and change the private_pda_spender to use the authenticated transfer. But I don't insist.
🎯 Purpose
This PR adds GroupKeyHolder to the wallet for group-owned private PDAs. A group of controllers shares a Group Master Secret (GMS). From it, each controller independently derives identical keys for any PDA the group owns, enabling private multisig and k-of-n patterns over existing PDA-based programs without changing those programs.
⚙️ Approach
key_protocol: GroupKeyHolder (core cryptography)
SHA256(domain_prefix || gms || pda_seed)producing NSK/NPK/VSK/VPK through the existing derivation chain.epochcounter +ratchet(rotation_salt)forward-hashes the GMS so removed members cannot derive future keys.seal_for(recipient_vpk)/unseal(sealed, own_vsk)encrypts GMS+epoch via ephemeral ECDH + domain-separated KDF + AES-256-GCM for distribution over untrusted channels.dangerous_raw_gmsto flag intent.key_protocol: NSSAUserData storage
group_key_holders: BTreeMap<String, GroupKeyHolder>field with#[serde(default)]for backward compatibility.group_pda_accounts: BTreeMap<AccountId, Account>local cache for decrypted group PDA state.get_group_key_holder/insert_group_key_holderaccessors.wallet: mask-3 transaction construction
PrivateGroupPda { group_label, program_id, seed }variant onPrivacyPreservingAccount.group_pda_preparationderives keys from GroupKeyHolder, computesAccountId::for_private_pda, reads PDA state from local cache.Test program:
group_pda_spendernssa/src/state.rsverify both paths at the circuit level.Integration test
🧪 How to Test
🔗 Dependencies
📋 PR Completion Checklist